// Copyright (c) 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

/**
*@describe:
*@author wfl19/Kristas
*@date 2021/04/10
 */

package gorm_plugin

import (
	"context"
	"fmt"
	"gitee.com/kristas/booting-go/framework/core/log"
	. "gorm.io/gorm/logger"
	"gorm.io/gorm/utils"
	"time"
)

type GormLoggerAdapter struct {
	LogLevel
	SlowThreshold                       time.Duration
	traceStr, traceErrStr, traceWarnStr string
	log                                 log.Logger `wire:""`
}

func NewGormLoggerAdapter(logger *GormLoggerAdapter) *GormLoggerAdapter {
	var (
		traceStr     = "%s\n[gorm][%.3fms][rows:%v] %s"
		traceWarnStr = "%s\n[%s]\n[gorm][%.3fms][rows:%v] %s"
		traceErrStr  = "%s\n[%s]\n[gorm][%.3fms][rows:%v] %s"
	)

	logger.traceStr = traceStr
	logger.traceWarnStr = traceWarnStr
	logger.traceErrStr = traceErrStr
	return logger
}

func (g *GormLoggerAdapter) LogMode(level LogLevel) Interface {
	g.LogLevel = level
	return g
}

func (g *GormLoggerAdapter) Info(ctx context.Context, s string, i ...interface{}) {
	g.log.Context(ctx).Info(s, i...)
}

func (g *GormLoggerAdapter) Warn(ctx context.Context, s string, i ...interface{}) {
	g.log.Context(ctx).Warn(s, i...)
}

func (g *GormLoggerAdapter) Error(ctx context.Context, s string, i ...interface{}) {
	g.log.Context(ctx).Error(s, i...)
}

func (g *GormLoggerAdapter) Trace(ctx context.Context, begin time.Time, fc func() (string, int64), err error) {
	if g.LogLevel > Silent {
		elapsed := time.Since(begin)
		switch {
		case err != nil && g.LogLevel >= Error:
			sql, rows := fc()
			if rows == -1 {
				g.Error(ctx, g.traceErrStr, utils.FileWithLineNum(), err, float64(elapsed.Nanoseconds())/1e6, "-", sql)
			} else {
				g.Error(ctx, g.traceErrStr, utils.FileWithLineNum(), err, float64(elapsed.Nanoseconds())/1e6, rows, sql)
			}
		case elapsed > g.SlowThreshold && g.SlowThreshold != 0 && g.LogLevel >= Warn:
			sql, rows := fc()
			slowLog := fmt.Sprintf("SLOW SQL >= %v", g.SlowThreshold)
			if rows == -1 {
				g.Warn(ctx, g.traceWarnStr, utils.FileWithLineNum(), slowLog, float64(elapsed.Nanoseconds())/1e6, "-", sql)
			} else {
				g.Warn(ctx, g.traceWarnStr, utils.FileWithLineNum(), slowLog, float64(elapsed.Nanoseconds())/1e6, rows, sql)
			}
		case g.LogLevel == Info:
			sql, rows := fc()
			if rows == -1 {
				g.Info(ctx, g.traceStr, utils.FileWithLineNum(), float64(elapsed.Nanoseconds())/1e6, "-", sql)
			} else {
				g.Info(ctx, g.traceStr, utils.FileWithLineNum(), float64(elapsed.Nanoseconds())/1e6, rows, sql)
			}
		}
	}
}
